
let _Vue = null

export default class VueRouter {

  static install(Vue) {
    // 1.判断当前插件是否被安装
    if (VueRouter.install.installed) {
      return
    }
    VueRouter.install.installed = true

    // 2.把Vue构造函数记录到全局变量
    _Vue = Vue

    // 3.把创建Vue实例时候传入的router对象注入到Vue实例上
    // 混入
    _Vue.mixin({
      beforeCreate() {
        // 组件中也会调用，加上判断
        if (this.$options.router) { // 组件不执行
          _Vue.prototype.$router = this.$options.router
          this.$options.router.init()
        }
      }
    })
  }

  constructor(options) {
    this.options = options
    this.routeMap = {}
    this.data = _Vue.observable({
      current: '/'
    })
  }

  init() {
    this.initEvents();
    this.createRouteMap()
    this.initComponents(_Vue)
  }

  // 获取当前的 hash 值
  getHash() {
    return window.location.hash.slice(1) || '/'
  }

  getFromAndTo (e) {
    let from, to;
    if (e.newURL) {
      from = e.oldURL.split('#')[1];
      to = e.newURL.split("#")[1];
    } else {
      from = "";
      to = this.getHash();
    }
    return { from, to }
  }
  
  onHashChange (e) {
    let hash = this.getHash();
    let router = this.routeMap[hash];
    let { from, to } = this.getFromAndTo(e);
    if (router.beforeEnter) {
      router.beforeEnter(from, to, () => {
        this.data.current = hash;
      })
    } else {
      this.data.current = hash;
    }
  }

  createRouteMap() {
    // 遍历所有的路由规则，把路由规则解析成键值对的形式，存储到 routeMap 中
    this.options.routes.forEach(route => {
      this.routeMap[route.path] = route.component
    })
  }

  initComponents(Vue) {
    Vue.component('router-link', {
      props: {
        to: String
      },
      render(h) {
        return h('a', {
          attrs: {
            href: `#${this.to}`
          }
        }, [this.$slots.default])
      }
    })
    const self = this
    Vue.component('router-view', {
      render(h) {
        // self.data.current // 当前路由地址
        const component = self.routeMap[self.data.current]
        return h(component)
      }
    })

  }

  initEvents () {
    // 监听 hashchang 改变
    window.addEventListener("hashchange", this.onHashChange.bind(this), false)
    // 监听初始化页面
    window.addEventListener("load", this.onHashChange.bind(this), false)
  }

}